package com.huiquan.vocab.utils;

import com.huiquan.framework.utils.ArrayUtil;
import com.huiquan.framework.utils.CollectionUtil;
import com.huiquan.synonymy.dao.SynonymyWordDao;
import com.huiquan.vocab.constant.VocabConstant;
import com.huiquan.vocab.dao.VocabDyadDao;
import com.huiquan.vocab.dao.VocabDyadRemoveDao;
import com.huiquan.vocab.dao.VocabDyadStdDao;
import com.huiquan.vocab.dao.VocabElementLabelDao;
import com.huiquan.vocab.domain.HiveSymptomDyadStd;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.*;

@Service
public class SymptomStdDyadUtil {

	protected final Logger log = LoggerFactory.getLogger(this.getClass());

	@Autowired
	private VocabDyadDao vocabDyadDao;
	@Autowired
	private VocabDyadStdDao vocabDyadStdDao;
	@Autowired
	private VocabElementLabelDao vocabElementLabelDao;
	@Autowired
	private VocabDyadRemoveDao vocabDyadRemoveDao;
	@Autowired
	private SynonymyWordDao synonymyWordDao;

	private boolean initFlag = false;
	private boolean stdInitFlag = false;

	public void resetInitFlag() {
		initFlag = false;
		stdInitFlag = false;
	}

	/** 所有元素的同义词. */
	private Map<String, Map<String, String>> synonymMap = new HashMap<>();

	/**
	 * 根据症状分词获取对应症状标准词及二元组
	 * 
	 * @param symptomArray
	 *            症状分词
	 * @param partPattern
	 *            属性
	 * @return
	 */
	public List<HiveSymptomDyadStd> getSymptomStd(String symptomArray, String partPattern, String cnt) {

		// 初始化元素同义词
		if (!stdInitFlag) {
			initSynonym();
		}

		// 将症状分词标准化
		String[] symptom = getStdSymptomArray(symptomArray, partPattern);

		return getSymptomDyadStd(symptom[0], symptom[1], symptom[0], cnt);
	}

	/**
	 * 根据症状分词、分词属性和元素标准词获取症状分词标准词
	 * 
	 * @param symptomArray
	 * @return
	 */
	private String[] getStdSymptomArray(String symptomArray, String partPattern) {
		String[] symptom = new String[2];

		// 原始症状的分词和属性
		String[] properties = partPattern.substring(1).split(",");
		String[] words = symptomArray.substring(1).split(",");

		// 最终获取的标准症状和属性
		String stdSymptomArray = ",";
		String stdSymptomPartPattern = ",";

		for (int i = 0; i < properties.length; i++) {
			// 如果si或其标准词对应有o+s的标准词（二元组），则使用该标准词
			if (properties[i].equals("si")) {
				String osSymptom = si2os.get(words[i]); // 直接用该si查询
				String siStd = synonymMap.get("si").get(words[i]);
				if (osSymptom == null && siStd != null) { // 如果直接的si没有对应o+s则用该si的标准词来查询
					osSymptom = si2os.get(siStd);
				}
				if (osSymptom != null) {
					String[] osArray = osSymptom.split("" + (char) 1)[0].substring(1).split(",");
					String[] osPartPattern = osSymptom.split("" + (char) 1)[1].substring(1).split(",");
					for (int j = 0; j < osPartPattern.length; j++) {
						Map<String, String> sub = synonymMap.get(osPartPattern[j]);
						String std = "";
						if (sub != null && (std = sub.get(osArray[j])) != null) {
							stdSymptomArray += std + ",";
						} else {
							stdSymptomArray += osArray[j] + ",";
						}
						stdSymptomPartPattern += osPartPattern[j] + ",";
					}
					continue; // 该si处理完成
				}
			}

			// 如果没有特殊处理，则都是使用元素同义词的标准词来处理
			Map<String, String> sub = synonymMap.get(properties[i]);
			String std = "";
			if (sub != null && (std = sub.get(words[i])) != null) {
				stdSymptomArray += std + ",";
			} else {
				stdSymptomArray += words[i] + ",";
			}
			stdSymptomPartPattern += properties[i] + ",";
		}

		symptom[0] = stdSymptomArray;
		symptom[1] = stdSymptomPartPattern;

		return symptom;
	}

	// si标准词是o+s的数据
	Map<String, String> si2os = new HashMap<>();

	/**
	 * 将所有的同义词导出，然后维护到map中
	 */
	private void initSynonym() {

		List<Map<String, String>> si2osList = vocabDyadDao.retrieveSi2OS();
		for (Map<String, String> map : si2osList) {
			si2os.put(map.get("si").replace(",", ""), map.get("array") + (char) 1 + map.get("part_pattern"));
		}

		synonymMap = new HashMap<>();

		List<Map<String, String>> synonym = synonymyWordDao.retrieveElementSynonymByProperty("");
		List<Map<String, String>> synonymO = synonymyWordDao.retrieveElementSynonymO();

		// o的同义词特殊处理
		Map<String, String> oSub = synonymMap.get("o");
		if (oSub == null) {
			oSub = new HashMap<>();
			synonymMap.put("o", oSub);
		}
		for (Map<String, String> temp : synonymO) {
			oSub.put(temp.get("word"), temp.get("std"));
		}

		// 除了o之外的同义词统一处理
		for (Map<String, String> temp : synonym) {
			String property = temp.get("property");
			String word = temp.get("word");
			String std = temp.get("std");

			if (property.indexOf("o") < 0) {
				Map<String, String> sub = synonymMap.get(property);
				if (sub == null) {
					sub = new HashMap<>();
					synonymMap.put(property, sub);
				}

				sub.put(word, std);
			}
		}

		stdInitFlag = true;

	}

	/** 白名单. */
	private Map<String, Map<String, String>> whitelistMap = new HashMap<>();
	/** 黑名单. */
	private Map<String, List<String>> blacklistMap = new HashMap<>();
	/** p+o需合并的词，key是分词标准词，value是对应二元组标准词的标准分词合并结果. */
	private Map<String, String> poMerge = new HashMap<>();
	/** de中可修饰o的. */
	private List<String> deDecorateO = new ArrayList<>();
	/** o+oa remove原词. */
	private List<List<String>> oOaRemoveArrayList = new ArrayList<>();
	/** o+oa remove结果词. */
	private List<List<String>> oOaRemoveResultList = new ArrayList<>();
	/** o+in+s remove. */
	private Map<String, String> oInSRemoveMap = new HashMap<>();
	/** o+s核心词中需要保留多个o的. */
	private List<String> multiOCombineS = new ArrayList<>();
	/** 忽略P的规则. */
	private Map<String, String> osIgnorePStd = new HashMap<>();

	/**
	 * 初始化二元组和二元组标准词中的标准分词，由于该内容放在跑批中执行会有数据库表的冲突，所以将其在跑批之前执行，每天晚上执行一次即可
	 */
	public void initDyadStd() {
		// 初始化二元组的标准分词
		vocabDyadDao.initStdArray();

		// 初始化二元组标准词的标准分词
		vocabDyadStdDao.initStdArray();

		// 初始化忽略p数据中的标准词
		vocabDyadDao.initOSIgnoreP();
	}

	/**
	 * <pre>
	 * 初始化全局变量中的规则
	 * 规则中所有的元素都是经过同义词转化为标准词之后的结果
	 * </pre>
	 */
	private void initRule() {

		whitelistMap = new HashMap<>();
		blacklistMap = new HashMap<>();
		poMerge = new HashMap<>();
		deDecorateO = new ArrayList<>();
		oOaRemoveArrayList = new ArrayList<>();
		oOaRemoveResultList = new ArrayList<>();
		oInSRemoveMap = new HashMap<>();
		multiOCombineS = new ArrayList<>();
		osIgnorePStd = new HashMap<>();

		// 去获取二元组对应的分词标准词及类型
		List<Map<String, String>> arrayAndStdDyad = vocabDyadDao.retrieveCheckedArrayAndStdDyad();

		Map<String, String> whitelist = null;
		for (Map<String, String> obj : arrayAndStdDyad) {
			String type = obj.get("type");
			String array = obj.get("array");
			String stdDyad = obj.get("std_dyad");
			String dyadProp = obj.get("dyad_prop");
			String flag = obj.get("flag");

			// 初始化黑白名单
			if ("1".equals(flag)) {
				// 将数据添加入黑名单中
				List<String> blacklist = blacklistMap.get(type);
				if (blacklist == null) {
					blacklist = new ArrayList<>();
					blacklistMap.put(type, blacklist);
				}
				blacklist.add(array);
			} else if ("0".equals(flag)) {
				// 将数据添加入白名单
				whitelist = whitelistMap.get(type);
				if (whitelist == null) {
					whitelist = new HashMap<>();
					whitelistMap.put(type, whitelist);
				}
				whitelist.put(array, stdDyad + "\t" + dyadProp);
			}

			// 初始化p+o需合并的词
			String mergeFlag = obj.get("merge_flag");
			if ("p+o".equals(type) && "1".equals(mergeFlag)) {
				poMerge.put(array, stdDyad.replace(",", ""));
			}
		}

		// o+oa remove初始化
		List<String> oOaRemovelist = vocabDyadRemoveDao.retrieveRemove4ExportRuleFile("o+oa");
		for (String remove : oOaRemovelist) {
			if (!remove.isEmpty() && remove.indexOf("\t") > -1) {
				// o+oa的remove用分词的第一个词语做为key分流

				List<String> array = Arrays.asList(remove.split("\t")[0].substring(1).split(","));
				List<String> result = Arrays.asList(remove.split("\t")[1].substring(1).split(","));

				oOaRemoveArrayList.add(array);
				oOaRemoveResultList.add(result);
			}
		}

		// o+in+s remove初始化
		List<String> oInSRemovelist = vocabDyadRemoveDao.retrieveRemove4ExportRuleFile("o+in+s");
		for (String remove : oInSRemovelist) {
			if (!remove.isEmpty() && remove.indexOf("\t") > -1) {
				oInSRemoveMap.put(remove.split("\t")[0], remove.split("\t")[1]);
			}
		}

		// 忽略P的规则初始化
		List<Map<String, String>> oSIgnoreP = vocabDyadDao.retrieveOSIgnoreP();
		for (Map<String, String> map : oSIgnoreP) {
			osIgnorePStd.put(map.get("o") + map.get("s"), map.get("type"));
		}

		// de中可以修饰o的列表
		deDecorateO = vocabElementLabelDao.retrieveDecorateOWord();

		// o+s核心词中需要保留多个o的
		multiOCombineS = vocabDyadDao.retrieveMultiOCombineS();

		initFlag = true;
	}

	String tempOStd, tempSStd, tempPStd, tempPOInSStd;
	String tempO, tempS, tempSi, tempP, tempPOMerge, tempPOInS, tempInS;
	String propertyP, propertyO, propertyPOInS, propertyInS;
	List<String> oOStdVocabList, oSStdVocabList, deStdList;
	List<String> oOVocabList, oVocabList, oOPropretyList, deList, oSVocabList, oSPropertyList;
	boolean hasIn, afterS;
	String symptomStdArray = ",", symptomStdProp = ","; // 症状标准词
	String os2si = "";
	private boolean deleteFlag = false;

	private void initTempParam() {
		tempOStd = "";
		tempSStd = "";
		tempPStd = "";
		tempPOInSStd = "";

		tempO = "";
		tempS = "";
		tempSi = "";
		tempP = "";
		tempPOMerge = "";
		tempPOInS = "";
		tempInS = "";

		propertyP = "";
		propertyO = "";
		propertyPOInS = "";
		propertyInS = "";

		oOStdVocabList = new ArrayList<>();
		oSStdVocabList = new ArrayList<>();
		deStdList = new ArrayList<>();

		oOVocabList = new ArrayList<>();
		oVocabList = new ArrayList<>();
		oOPropretyList = new ArrayList<>();
		deList = new ArrayList<>();
		oSVocabList = new ArrayList<>();
		oSPropertyList = new ArrayList<>();

		hasIn = false;
		afterS = false;

		symptomStdArray = ",";
		symptomStdProp = ",";

		os2si = "";
		deleteFlag = false;
	}

	/**
	 * 根据症状分词及其标准分词获取对应症状标准词及二元组
	 * 
	 * @param symptomArray
	 *            症状分词
	 * @param partPattern
	 *            属性
	 * @param stdArray
	 *            症状标准分词
	 * @return
	 */
	public List<HiveSymptomDyadStd> getSymptomDyadStd(String symptomArray, String partPattern, String stdArray,
			String cnt) {

		if (!initFlag) {
			initRule();
		}

		initTempParam();

		List<HiveSymptomDyadStd> result = new ArrayList<>();

		// 校验参数
		if (!checkParam(symptomArray, partPattern, stdArray)) {
			return result;
		}

		// 如果该症状词就是一个正确的二元组，则直接返回该二元组标准词
		String originType = getTypeByPartPattern(partPattern,symptomArray);
		if (originType != null) {
			List<HiveSymptomDyadStd> originDyadStd = getOriginDyadStd(symptomArray, partPattern, cnt, originType);
			if (!originDyadStd.isEmpty()) {
				return originDyadStd;
			}
		}

		List<String> arrayList = ArrayUtil.asList(symptomArray.substring(1).split(","));
		List<String> stdArrayList = ArrayUtil.asList(stdArray.substring(1).split(","));
		List<String> propertyList = ArrayUtil.asList(partPattern.substring(1).split(","));

		// 忽略单双左右
		ignoreP(stdArrayList, propertyList, arrayList);

		// 拆分症状，获取各种二元组
		for (int i = 0; i < propertyList.size(); i++) {
			// 获取p+o
			if (propertyList.get(i).equals("p")) {
				tempPStd += stdArrayList.get(i) + ",";
				tempP += arrayList.get(i) + ",";
				propertyP += "p,";

				tempPOInSStd += stdArrayList.get(i) + ",";
				tempPOInS += arrayList.get(i) + ",";
				propertyPOInS += propertyList.get(i) + ",";
			} else if (propertyList.get(i).indexOf("o") > -1) {
				if (tempOStd.isEmpty() && !tempPStd.isEmpty()) {
					// 之前没有o只有p
					String pOa = "," + tempP + arrayList.get(i) + ",";
					String pOp = "," + propertyP + propertyList.get(i) + ",";
					if (!blacklistMap.get("p+o").contains(pOa)) {
						// 不在黑名单中则加入结果
						addDyad2Result("p+o", pOa, pOp, result);

						// 如果和p可以合并则维护进临时变量tempPOMerge
						setTempPOMergeByCurrentO(pOa);

						setSymptomStd("," + tempPStd, "," + propertyP);
					} else {
						deleteFlag = true;
					}

				} else if (!tempOStd.isEmpty() && tempPStd.isEmpty()) {
					// 之前没有p只有o
					setOVocabListByPo();

					setSymptomStd("," + tempOStd + ",", "," + propertyO + ",");

				} else if (!tempOStd.isEmpty() && !tempPStd.isEmpty()) {
					// 之前有p也有o
					String fullPCurrentO = "," + tempP + arrayList.get(i) + ",";
					String fullPPrevO = "," + tempO + "," + tempP;
					if (!blacklistMap.get("p+o").contains(fullPCurrentO)) {
						// 将上一个o添加入o列表中
						setOVocabListByPo();
						// 如果和p可以合并则维护进临时变量tempPOMerge
						setTempPOMergeByCurrentO(fullPCurrentO);

						// 当前的o匹配前面所有的p如果不在黑名单中，则加入结果
						String pOp = "," + propertyP + propertyList.get(i) + ",";
						addDyad2Result("p+o", fullPCurrentO, pOp, result);

						setSymptomStd("," + tempOStd + ",", "," + propertyO + ",");
						setSymptomStd("," + tempPStd, "," + propertyP);

					} else if (!blacklistMap.get("p+o").contains(fullPPrevO)) {
						// 上一个o匹配前面所有的p如果不在黑名单中，则加入结果
						String pOp = "," + propertyO + "," + propertyP;
						addDyad2Result("p+o", fullPPrevO, pOp, result);

						// 如果所有p和上一个o组合为正确，将o或p+o组合放入o列表
						if (poMerge.get(fullPPrevO) != null) {
							oOStdVocabList.add(poMerge.get(fullPPrevO));
							oOVocabList.add(poMerge.get(fullPPrevO));

							oSStdVocabList.add(poMerge.get(fullPPrevO));
							oSVocabList.add(poMerge.get(fullPPrevO));
						} else {
							setOVocabListByPo();
						}

						tempPOMerge = "";

						setSymptomStd("," + tempOStd + ",", "," + propertyO + ",");
						setSymptomStd("," + tempPStd, "," + propertyP);

					} else {
						// 如果p需要拆分开和两个o分担
						String[] pArray = tempP.split(",");

						boolean flag = false;

						// 如果p的个数只有一个则不需要拆分
						if (pArray.length > 2) {
							String currentPO = tempP + arrayList.get(i) + ",";
							String prevPO = "," + tempO;
							String currentProperty = propertyP + propertyList.get(i) + ",";
							String prevProperty = "," + propertyO;
							for (int j = 0; j < pArray.length; j++) {
								prevPO += "," + pArray[j];
								prevProperty += ",p";
								currentPO = currentPO.substring(pArray[j].length() + 1);
								currentProperty = currentProperty.substring(2);
								if (!blacklistMap.get("p+o").contains(prevPO + ",")
										&& !blacklistMap.get("p+o").contains("," + currentPO)) {
									addDyad2Result("p+o", prevPO + ",", prevProperty + ",", result);
									addDyad2Result("p+o", "," + currentPO, "," + currentProperty, result);

									// 处理上一个o，如果能合并成po组合则合并后加入列表
									if (poMerge.get(prevPO) != null) {
										oOStdVocabList.add(poMerge.get(prevPO));
										oOVocabList.add(poMerge.get(prevPO));

										oSStdVocabList.add(poMerge.get(prevPO));
										oSVocabList.add(poMerge.get(prevPO));
									} else {
										setOVocabListByPo();
									}

									// 如果和p可以合并则维护进临时变量tempPOMerge
									setTempPOMergeByCurrentO("," + currentPO);

									setSymptomStd("," + tempOStd + ",", "," + propertyO + ",");
									setSymptomStd("," + tempPStd, "," + propertyP);

									// p+o并不是全部错误
									flag = true;
									break;
								}
							}

							if (!flag) {
								// p+o都是错误的
								setOVocabListByPo();
								setSymptomStd("," + tempOStd + ",", "," + propertyO + ",");
								deleteFlag = true;
							}
						} else {
							setOVocabListByPo();
							setSymptomStd("," + tempOStd + ",", "," + propertyO + ",");
							deleteFlag = true;
						}
					}
				}

				oSPropertyList.add(propertyList.get(i));
				oOPropretyList.add(propertyList.get(i));
				tempOStd = stdArrayList.get(i);
				tempO = arrayList.get(i);
				oVocabList.add(stdArrayList.get(i));
				tempPOInSStd += stdArrayList.get(i) + ",";
				tempPOInS += arrayList.get(i) + ",";
				propertyPOInS += propertyList.get(i) + ",";
				tempPStd = "";
				tempP = "";
				propertyP = "";
				propertyO = propertyList.get(i);

			} else {
				// 不是o或者p了，判断是否有p+o进入结果
				checkFullPPrevO(result);

				setSymptomStd("," + stdArrayList.get(i) + ",", "," + propertyList.get(i) + ",");

				if (propertyList.get(i).equals("s")) {
					// 类型为s的元素记录下来，后面统一处理s+de、o+s
 					tempSStd = stdArrayList.get(i);
					tempS = arrayList.get(i);

					tempPOInSStd += stdArrayList.get(i) + ",";
					tempPOInS += arrayList.get(i) + ",";
					propertyPOInS += propertyList.get(i) + ",";
					tempInS += arrayList.get(i) + ",";
					propertyInS += propertyList.get(i) + ",";

					oSStdVocabList.add(tempSStd);
					oSVocabList.add(tempS);
					oSPropertyList.add("s");

					afterS = true;
				} else if (propertyList.get(i).equals("si")) {
					// 类型为si的元素记录下来，后面统一处理si+de
					tempSi = stdArrayList.get(i);

					afterS = true;
				} else if (propertyList.get(i).equals("de")) {
					// 类型为de的元素记录下来，后面统一处理s+de、si+de、o+de
					if (afterS) {
						deList.add(arrayList.get(i) + "\t1");
					} else {
						deList.add(arrayList.get(i) + "\t0");
					}
					deStdList.add(stdArrayList.get(i));
				} else if (propertyList.get(i).equals("in")) {
					// 类型为in的元素记录下来，后面统一处理o+in+s、in+s
					tempPOInSStd += stdArrayList.get(i) + ",";
					tempPOInS += arrayList.get(i) + ",";
					propertyPOInS += propertyList.get(i) + ",";
					tempInS += arrayList.get(i) + ",";
					propertyInS += propertyList.get(i) + ",";
					hasIn = true;
				}
			}
		}

		// 结束循环需要校验最后是否还有p+o没有校验
		if (!tempOStd.isEmpty() && tempPStd.isEmpty()) {
			setOVocabListByPo();
			setSymptomStd("," + tempOStd + ",", "," + propertyO + ",");
		} else if (!tempOStd.isEmpty() && !tempPStd.isEmpty()) {
			String fullPPrevOStd = "," + tempOStd + "," + tempPStd;
			String fullPPrevO = "," + tempO + "," + tempP;
			String pOp = "," + propertyO + "," + propertyP;
			if (!blacklistMap.get("p+o").contains(fullPPrevO)) {
				if (poMerge.get(fullPPrevO) != null) {
					oOStdVocabList.add(poMerge.get(fullPPrevO));
					oOVocabList.add(poMerge.get(fullPPrevO));

					oSStdVocabList.add(poMerge.get(fullPPrevO));
					oSVocabList.add(poMerge.get(fullPPrevO));
				} else {
					setOVocabListByPo();
				}

				addDyad2Result("p+o", fullPPrevO, pOp, result);
				setSymptomStd(fullPPrevOStd, pOp);
			} else {
				deleteFlag = true;
				setSymptomStd("," + tempOStd + ",", "," + propertyO + ",");
				setOVocabListByPo();
			}
		}

		checkSDeAndODe(result);
		checkSiDe(result);
		if (!checkInS(result)) {
			result = new ArrayList<>();
		}

		if (!checkOO(result) && !hasIn) {
			result = new ArrayList<>();
		}

		if (!checkOS(result) && !hasIn) {
			result = new ArrayList<>();
		}

		if (!result.isEmpty()) {
			if (!os2si.isEmpty() && partPattern.indexOf("si") < 0) {
				String[] properties = symptomStdProp.substring(1).split(",");
				String[] words = symptomStdArray.substring(1).split(",");
				symptomStdArray = ",";
				symptomStdProp = ",";
				for (int i = 0; i < properties.length; i++) {
					if (properties[i].equals("p") || properties[i].indexOf("o") > -1) {

					} else if (properties[i].equals("s")) {
						symptomStdArray += os2si + ",";
						symptomStdProp += "si,";
					} else {
						symptomStdArray += words[i] + ",";
						symptomStdProp += properties[i] + ",";
					}
				}
			} else {
				// 将二元组的同义词加入到标准症状中
				dyadStdChangeSymptomStd(result, symptomArray);
			}

			String dyadFlag = "0";
			for (HiveSymptomDyadStd temp : result) {
				temp.setSymptom(symptomArray.replace(",", ""));
				temp.setPartPattern(partPattern);
				temp.setSymptomArray(symptomArray);
				temp.setStdSymptom(symptomStdArray.replace(",", ""));
				temp.setStdSymptomArray(symptomStdArray);
				temp.setStdPartPattern(symptomStdProp);
				temp.setCnt(cnt);
				if (temp.getDyadFlag().equals("-1")) {
					dyadFlag = "-1";
				}
			}
			if (deleteFlag) {
				dyadFlag = "1";
			}
			for (HiveSymptomDyadStd temp : result) {
				temp.setDyadFlag(dyadFlag);
			}
		} else {
			HiveSymptomDyadStd temp = new HiveSymptomDyadStd();
			temp.setSymptom(symptomArray.replace(",", ""));
			temp.setPartPattern(partPattern);
			temp.setSymptomArray(symptomArray);
			temp.setStdSymptom(symptomStdArray.replace(",", ""));
			temp.setStdSymptomArray(symptomStdArray);
			temp.setStdPartPattern(symptomStdProp);
			temp.setCnt(cnt);
			if (",si,".equals(symptomStdProp)) {
				temp.setDyadStdPartPattern(symptomStdProp);
				temp.setDyadStdArray(symptomStdArray);
				temp.setDyadPartPattern(symptomStdProp);
				temp.setDyadArray(symptomStdArray);
				temp.setDyadFlag("0");
			} else {
				temp.setDyadStdPartPattern("");
				temp.setDyadStdArray("");
				temp.setDyadPartPattern("");
				temp.setDyadArray("");
				temp.setDyadFlag("1");
			}
			result.add(temp);
		}

		return result;
	}

	private String getTypeByPartPattern(String partPattern,String symptom) {

		// 判断是否有si
		boolean haveSi = getExistByProperty(partPattern, "si");
		// 判断是否有in
		boolean haveIn = getExistByProperty(partPattern, "in");
		// 判断是否有s
		boolean haveS = getExistByProperty(partPattern, "s");
		// 判断是否有o
		boolean haveO = getExistByProperty(partPattern, "o");
		// 判断是否有de
		boolean haveDe = getExistByProperty(partPattern, "de");
		// 判断是否有p
		boolean haveP = getExistByProperty(partPattern, "p");

		if (haveSi) {
			if (haveDe) {
				return VocabConstant.DYAD_SI_DE;
			} else {
				return VocabConstant.DYAD_O_S;
			}
		} else {
			if (haveIn) {
				if (haveO && !haveS) {
					return VocabConstant.DYAD_O_IN;
				}
				if (haveO && haveS) {
					return VocabConstant.DYAD_O_IN_S;
				}
				if (haveS && !haveO) {
					return VocabConstant.DYAD_IN_S;
				}
			} else {
				if (haveS) {
					if (haveDe && !haveO && !haveP) {
						return VocabConstant.DYAD_S_DE;
					} else if (haveO && !haveDe && !haveP) {
						return VocabConstant.DYAD_O_S;
					}
				} else if (haveO) {
					log.error("没有in/si/s应该不存在该症状，partPattern=" + partPattern +"symptom ="+symptom);
				}
			}
		}

		return null;
	}

	private boolean getExistByProperty(String partPattern, String property) {
		boolean exists = false;
		if (partPattern.indexOf(property) > -1) {
			exists = true;
		}
		return exists;
	}

	private List<HiveSymptomDyadStd> getOriginDyadStd(String symptomArray, String partPattern, String cnt,
			String originType) {
		List<HiveSymptomDyadStd> originDyadStd = new ArrayList<>();

		Map<String, String> map = whitelistMap.get(originType);
		String std = map.get(symptomArray);
		if (std != null && !std.isEmpty()) {
			String dyadStdArray = std.split("\t")[0];
			String dyadStdPartPattern = std.split("\t")[1];

			HiveSymptomDyadStd dyadStd = new HiveSymptomDyadStd();
			dyadStd.setDyadStdArray(dyadStdArray);
			dyadStd.setDyadStdPartPattern(dyadStdPartPattern);
			dyadStd.setDyadArray(dyadStdArray);
			dyadStd.setDyadPartPattern(dyadStdPartPattern);
			dyadStd.setDyadType(originType);
			dyadStd.setDyadFlag("0");

			dyadStd.setSymptom(dyadStdArray.replace(",", ""));
			dyadStd.setPartPattern(dyadStdPartPattern);
			dyadStd.setSymptomArray(dyadStdArray);
			dyadStd.setStdSymptom(dyadStdArray.replace(",", ""));
			dyadStd.setStdSymptomArray(dyadStdArray);
			dyadStd.setStdPartPattern(dyadStdPartPattern);
			dyadStd.setCnt(cnt);

			originDyadStd.add(dyadStd);
		}
		return originDyadStd;
	}

	private void dyadStdChangeSymptomStd(List<HiveSymptomDyadStd> result, String symptomArray) {
		// 先构建二元组对应词语的数组，并记录有个数变化的二元组
		String[] properties = symptomStdProp.substring(1).split(",");
		String[] words = symptomStdArray.substring(1).split(",");
		List<String[]> dyadWordsList = new ArrayList<>(); // 二元组分词对应数组
		List<String[]> dyadPropertiesList = new ArrayList<>(); // 二元组属性对应数组
		List<List<Integer>> dyadIndexList = new ArrayList<>(); // 二元组对应下标集合
		List<Integer> wordsNumChangeIndex = new ArrayList<>(); // 元素个数变化的二元组下标集合

		for (int k = 0; k < result.size(); k++) {
			HiveSymptomDyadStd std = result.get(k);

			String[] dws = std.getDyadArray().substring(1).split(",");
			String[] dps = std.getDyadPartPattern().substring(1).split(",");
			String[] dwsStd = std.getDyadStdArray().substring(1).split(",");
			String[] dpsStd = std.getDyadStdPartPattern().substring(1).split(",");

			boolean propertyChangeFlag = false;
			if (dps.length != dpsStd.length) {
				propertyChangeFlag = true;
				wordsNumChangeIndex.add(k);
			} else {
				for (int i = 0; i < dps.length; i++) {
					if (!dps[i].equals(dpsStd[i]) && (dps[i].indexOf("o") < 0 || dpsStd[i].indexOf("o") < 0)) {
						// 如果属性有不同并且不是o和oa的情况则表示属性有变
						propertyChangeFlag = true;

						wordsNumChangeIndex.add(k);
						break;
					}
				}
			}

			String[] dyadWords = new String[properties.length];
			dyadWordsList.add(dyadWords);
			String[] dyadProperties = new String[properties.length];
			dyadPropertiesList.add(dyadProperties);
			List<Integer> dyadIndex = new ArrayList<>();
			dyadIndexList.add(dyadIndex);

			// 循环元素与二元组中匹配，匹配上在数组对应位置上放上标准化的词语
			for (int i = 0; i < properties.length; i++) {
				for (int j = 0; j < dps.length; j++) {
					// 如果词和属性相同则表示元素匹配，若标准化有属性变化则将该二元组放置在最后的元素位置上
					if (words[i].equals(dws[j]) && properties[i].equals(dps[j])) {
						if (propertyChangeFlag) {
							if (j == dps.length - 1) {
								dyadWords[i] = std.getDyadStdArray().substring(1, std.getDyadStdArray().length() - 1);
								dyadProperties[i] = std.getDyadStdPartPattern().substring(1,
										std.getDyadStdPartPattern().length() - 1);
							} else {
								dyadWords[i] = "";
								dyadProperties[i] = "";
							}
						} else {
							dyadWords[i] = dwsStd[j];
							dyadProperties[i] = dpsStd[j];
						}

						dyadIndex.add(i);
					}
				}
			}
		}

		// 判断有个数变化的二元组是否与其他二元组有元素冲突，如果有则放弃个数变化的二元组
		for (int k = wordsNumChangeIndex.size() - 1; k >= 0; k--) {
			int i = wordsNumChangeIndex.get(k);
			List<Integer> changeIndex = dyadIndexList.get(i);
			for (List<Integer> temp : dyadIndexList) {
				List<Integer> changeIndexCopy = new ArrayList<>();
				changeIndexCopy.addAll(changeIndex);
				changeIndexCopy.retainAll(temp);

				if (!temp.equals(changeIndex) && !changeIndexCopy.isEmpty()) {
					dyadWordsList.remove(i);
					dyadPropertiesList.remove(i);
					break;
				}
			}
		}

		// 拼凑出症状标准词
		for (int k = 0; k < dyadWordsList.size(); k++) {
			String[] dyadWords = dyadWordsList.get(k);
			String[] dyadProperties = dyadPropertiesList.get(k);
			for (int i = 0; i < dyadWords.length; i++) {
				if (dyadWords[i] != null) {
					words[i] = dyadWords[i];
					properties[i] = dyadProperties[i];
				}
			}
		}
		symptomStdProp = ",";
		symptomStdArray = ",";
		for (int k = 0; k < properties.length; k++) {
			if (!words[k].isEmpty()) {
				symptomStdArray += words[k] + ",";
				symptomStdProp += properties[k] + ",";
			}
		}

		// 重置二元组
		for (int k = 0; k < dyadIndexList.size(); k++) {
			List<Integer> dyadIndex = dyadIndexList.get(k);
			String dyadArray = ",";
			String dyadPartPattern = ",";
			for (int i : dyadIndex) {
				if (words[i] != null && !words[i].isEmpty()) {
					dyadArray += words[i] + ",";
					dyadPartPattern += properties[i] + ",";
				}
			}

			HiveSymptomDyadStd std = result.get(k);
			std.setDyadArray(dyadArray);
			std.setDyadPartPattern(dyadPartPattern);
		}
	}

	private void setSymptomStd(String array, String property) {
		symptomStdArray += array.substring(1);
		symptomStdProp += property.substring(1);
	}

	// 单双左右的标准词，现在默认系统里的，以后这个功能上线则按新需求来
	String danStd = "一侧";
	String shuangStd1 = "双侧";
	String shuangStd2 = "双";
	String zuoStd = "左";
	String youStd = "右";

	private void ignoreP(List<String> stdArrayList, List<String> propertyList, List<String> arrayList) {
		List<String> oTemp = new ArrayList<>();
		List<Integer> pIndexTemp = new ArrayList<>();

		// 是否忽略单双或左右，或者全部p忽略
		boolean danShuang = false;
		boolean zuoYou = false;
		boolean all = false;
		for (int i = 0; i < propertyList.size(); i++) {
			String property = propertyList.get(i);
			if (VocabConstant.ELEMENT_POSITION.equals(property)) {
				pIndexTemp.add(i);

			} else if (VocabConstant.ELEMENT_ORGAN.equals(property)
					|| VocabConstant.ELEMENT_ORGAN_ADITIONAL.equals(property)) {
				oTemp.add(stdArrayList.get(i));

			} else if (VocabConstant.ELEMENT_SYMPTOM.equals(property)) {
				for (String o : oTemp) {
					// 判断o+s是否在忽略列表中
					String os = o + stdArrayList.get(i);
					String type = osIgnorePStd.get(os);
					if ("1".equals(type)) {
						// 1) 左右单双方位词可以都忽略
						danShuang = true;
						zuoYou = true;
					} else if ("3".equals(type)) {
						// 3) 分单双不分左右，忽略左右
						zuoYou = true;
					} else if ("4".equals(type)) {
						// 4) 方位词都忽略
						all = true;
					}
				}
			}
		}

		if (!pIndexTemp.isEmpty()) {
			if (all) {
				for (int i = pIndexTemp.size() - 1; i >= 0; i--) {
					stdArrayList.remove(pIndexTemp.get(i).intValue());
					propertyList.remove(pIndexTemp.get(i).intValue());
					arrayList.remove(pIndexTemp.get(i).intValue());
				}
			} else {
				for (int i = pIndexTemp.size() - 1; i >= 0; i--) {
					String pTemp = stdArrayList.get(pIndexTemp.get(i).intValue());
					boolean isDan = danStd.equals(pTemp);
					boolean isShuang = shuangStd1.equals(pTemp) || shuangStd2.equals(pTemp);
					if (danShuang && (isDan || isShuang)) {
						stdArrayList.remove(pIndexTemp.get(i).intValue());
						propertyList.remove(pIndexTemp.get(i).intValue());
						arrayList.remove(pIndexTemp.get(i).intValue());
					}

					boolean isZuo = zuoStd.equals(pTemp);
					boolean isYou = youStd.equals(pTemp);
					if (zuoYou && (isZuo || isYou)) {
						stdArrayList.remove(pIndexTemp.get(i).intValue());
						propertyList.remove(pIndexTemp.get(i).intValue());
						arrayList.remove(pIndexTemp.get(i).intValue());
					}
				}
			}
		}
	}

	private void checkFullPPrevO(List<HiveSymptomDyadStd> result) {
		if (!tempOStd.isEmpty() && !tempPStd.isEmpty()) {
			String pOaStd = "," + tempOStd + "," + tempPStd;
			String pOa = "," + tempO + "," + tempP;
			String pOp = "," + propertyO + "," + propertyP;
			if (!blacklistMap.get("p+o").contains(pOa)) {
				addDyad2Result("p+o", pOa, pOp, result);
				setSymptomStd(pOaStd, pOp);
			} else {
				setSymptomStd("," + tempOStd + ",", "," + propertyO + ",");
				deleteFlag = true;
			}
			// 如果所有p和上一个o组合为正确，将o或p+o组合放入o列表
			if (poMerge.get(pOa) != null) {
				tempPOMerge = poMerge.get(pOa);
			}
			setOVocabListByPo();
		} else if (!tempOStd.isEmpty()) {
			setOVocabListByPo();
			setSymptomStd("," + tempOStd + ",", "," + propertyO + ",");
		}

		tempPOMerge = "";
		tempOStd = "";
		tempPStd = "";
		tempO = "";
		tempP = "";
		propertyP = "";
		propertyO = "";
	}

	private void setOVocabListByPo() {
		if (!tempPOMerge.isEmpty()) {
			oOStdVocabList.add(tempPOMerge);
			oOVocabList.add(tempPOMerge);

			oSStdVocabList.add(tempPOMerge);
			oSVocabList.add(tempPOMerge);
		} else if (!tempOStd.isEmpty()) {
			oOStdVocabList.add(tempOStd);
			oOVocabList.add(tempO);

			oSStdVocabList.add(tempOStd);
			oSVocabList.add(tempO);
		}
	}

	private void setTempPOMergeByCurrentO(String pOa) {
		if (poMerge.get(pOa) != null) {
			tempPOMerge = poMerge.get(pOa);
		} else {
			tempPOMerge = "";
		}
	}

	/**
	 * 将二元组加入到返回结果中
	 * 
	 * @param type
	 * @param dyadArray
	 * @param dyadProp
	 * @param result
	 */
	private void addDyad2Result(String type, String dyadArray, String dyadProp, List<HiveSymptomDyadStd> result) {
		String dyadStdArray = dyadArray;
		String dyadStdPartPattern = dyadProp;

		for (String temp : type.split("\\+")) {
			if (dyadStdPartPattern.indexOf(temp) < 0) {
				return;
			}
		}

		HiveSymptomDyadStd hsds = new HiveSymptomDyadStd();

		String dyadFlag = "-1";
		Map<String, String> whitelist = whitelistMap.get(type);
		String stdDyad = whitelist.get(dyadArray);
		if (stdDyad != null) {
			dyadFlag = "0";

			dyadStdArray = stdDyad.split("\t")[0];
			dyadStdPartPattern = stdDyad.split("\t")[1];

			// 如果最终标准词是si属性的，则必是o+s替换成si，在症状标准词中将p、o和s都删除，换成si
			if (",si,".equals(dyadStdPartPattern)) {
				os2si = dyadStdArray.replace(",", "");
			}
		}

		for (HiveSymptomDyadStd exist : result) {
			if (exist.getDyadStdArray().equals(dyadStdArray)
					&& exist.getDyadStdPartPattern().equals(dyadStdPartPattern)) {
				return;
			}
		}

		hsds.setDyadStdArray(dyadStdArray);
		hsds.setDyadStdPartPattern(dyadStdPartPattern);
		hsds.setDyadArray(dyadArray);
		hsds.setDyadPartPattern(dyadProp);
		hsds.setDyadType(type);
		hsds.setDyadFlag(dyadFlag);

		result.add(hsds);
	}

	private boolean checkParam(String symptomArray, String partPattern, String stdArray) {

		int count1 = symptomArray.split(",").length;
		int count2 = partPattern.split(",").length;
		int count3 = stdArray.split(",").length;

		if (count1 == count2 && count2 == count3) {
			return true;
		}

		log.error("错误数据：" + symptomArray);
		return false;
	}

	private void checkDeDyad(String mp, String type, List<HiveSymptomDyadStd> result) {
		if (!deList.isEmpty() && !mp.isEmpty()) {
			// 如果s+de或si+de有错，则查看是否可以组合o+de，如果o+de不在黑名单中则通过
			a: for (int k = 0; k < deList.size(); k++) {
				String de = deList.get(k).split("\t")[0];
				String afterSFlag = deList.get(k).split("\t")[1];

				String d1 = "," + de + "," + mp + ",";
				String d2 = "," + mp + "," + de + ",";
				if (!blacklistMap.get(type).contains(d1) && !blacklistMap.get(type).contains(d2)) {
					if (afterSFlag.equals("1")) {
						addDyad2Result(type, d2, "," + type.split("\\+")[0] + ",de,", result);
					} else {
						addDyad2Result(type, d1, ",de," + type.split("\\+")[0] + ",", result);
					}
				} else {
					if (deDecorateO.contains(de)) {
						for (int i = 0; i < oVocabList.size(); i++) {
							String o = oVocabList.get(i);
							d1 = "," + de + "," + o + ",";
							d2 = "," + o + "," + de + ",";

							if (!blacklistMap.get("o+de").contains(d1)) {
								addDyad2Result("o+de", d1, ",de," + type.split("\\+")[1] + ",", result);
								continue a;

							} else if (!blacklistMap.get("o+de").contains(d2)) {
								addDyad2Result("o+de", d2, ",de," + type.split("\\+")[1] + ",", result);
								continue a;

							}
						}
					}
					// de需从症状标准词中去除
					String[] symptomStdArrays = symptomStdArray.substring(1).split(",");
					String[] symptomStdProps = symptomStdProp.substring(1).split(",");
					String deStd = deStdList.get(k);
					for (int j = 0; j < symptomStdProps.length; j++) {
						if (symptomStdProps[j].equals("de") && symptomStdArrays[j].equals(deStd)) {
							symptomStdProps[j] = "";
							symptomStdArrays[j] = "";
						}
					}
					symptomStdArray = "," + ArrayUtil.joinStringBySeparator(symptomStdArrays, ",") + ",";
					symptomStdProp = "," + ArrayUtil.joinStringBySeparator(symptomStdProps, ",") + ",";
					deleteFlag = true;
				}
			}
		}
	}

	private void checkSDeAndODe(List<HiveSymptomDyadStd> result) {
		// 循环de去组合s，如果有黑名单数据则返回错误
		checkDeDyad(tempS, "s+de", result);
	}

	private void checkSiDe(List<HiveSymptomDyadStd> result) {
		// 循环de去组合si，如果有黑名单数据则返回错误
		checkDeDyad(tempSi, "si+de", result);
	}

	private boolean checkInS(List<HiveSymptomDyadStd> result) {
		tempPOInSStd = "," + tempPOInSStd;
		tempPOInS = "," + tempPOInS;
		propertyPOInS = "," + propertyPOInS;
		// 如果有in则进入in+s的判断
		if (hasIn) {
			// 先判断o+in+s是否有remove
			if (oInSRemoveMap.get(tempPOInSStd) != null) {
				tempPOInS = "," + tempInS;
				propertyPOInS = "," + propertyInS;
			}
			if (blacklistMap.get("o+in+s").contains(tempPOInS) || blacklistMap.get("in+s").contains(tempPOInS)) {
				deleteFlag = true;
				return false;
			} else {
				addDyad2Result("in+s", tempPOInS, propertyPOInS, result);
			}
		}
		return true;
	}

	private boolean checkOO(List<HiveSymptomDyadStd> result) {
		if (oOStdVocabList.size() > 1) {
			boolean flag = true; // remove可以进行多次，每次remove后再重头循环查找一遍，直到有一次没有remove为止
			List<String> oOStdTemp, oOPropTemp, removeResult; // 临时变量记录remove后的临时信息，如果最终匹配成功则将临时转为正式
			List<String> oOTemp;
			int removeIndex, removeResultIndex;
			int loopCount = 0; // 一般不会超过三次，如果超过五次应该是出问题死循环了，往外抛异常

			remove: while (flag) {
				flag = false;

				String[] symptomStdArrays = symptomStdArray.substring(1).split(",");
				String[] symptomStdProps = symptomStdProp.substring(1).split(",");

				loopCount++;
				if (loopCount > 5) {
					throw new RuntimeException("o+oa remove循环超过五次！");
				}

				for (int i = 0; i < oOaRemoveArrayList.size(); i++) {
					List<String> removeArray = oOaRemoveArrayList.get(i);
					oOStdTemp = new ArrayList<>();
					oOTemp = new ArrayList<>();
					oOPropTemp = new ArrayList<>();

					removeResult = oOaRemoveResultList.get(i);
					removeIndex = 0;
					removeResultIndex = 0;

					if (oOStdVocabList.containsAll(removeArray)) {
						for (int j = 0; j < oOStdVocabList.size(); j++) { // 循环分词，逐一和remove分词比较，如果能匹配上就对比remove的结果词，并根据remove分词是否结束来判断该remove是否成功
							String oOStd = oOStdVocabList.get(j);
							String oO = oOVocabList.get(j);
							if (removeIndex < removeArray.size() && oOStd.equals(removeArray.get(removeIndex))) {
								if (removeResultIndex < removeResult.size()
										&& removeResult.get(removeResultIndex).equals(oOStd)) {
									// 结果词中还存在，则表示该词还保留
									oOStdTemp.add(oOStd);
									oOTemp.add(oO);
									oOPropTemp.add(oOPropretyList.get(j));

									removeResultIndex++;
								} else {
									// 结果此不存在，处理症状标准词
									for (int k = 0; k < symptomStdProps.length; k++) {
										if (symptomStdProps[k].indexOf("o") > -1 && oOStd.equals(symptomStdArrays[k])) {
											symptomStdProps[k] = "";
											symptomStdArrays[k] = "";
											break;
										}
									}

									// 处理o+s数据
									for (int k = 0; k < oSStdVocabList.size(); k++) {
										if (oSPropertyList.indexOf("o") > -1 && oOStd.equals(oSStdVocabList.get(k))) {
											oSStdVocabList.remove(k);
											oSVocabList.remove(k);
											oSPropertyList.remove(k);
											break;
										}
									}
								}

								removeIndex++;
							} else {
								// 没有和remove中数据匹配，则原词保留
								oOStdTemp.add(oOStd);
								oOTemp.add(oO);
								oOPropTemp.add(oOPropretyList.get(j));
							}
						}
						if (removeIndex == removeArray.size()) {
							// 表示与该remove完全匹配了，该remove成功
							oOStdVocabList = oOStdTemp;
							oOVocabList = oOTemp;
							oOPropretyList = oOPropTemp;

							symptomStdArray = "," + ArrayUtil.joinStringBySeparator(symptomStdArrays, ",") + ",";
							symptomStdProp = "," + ArrayUtil.joinStringBySeparator(symptomStdProps, ",") + ",";

							flag = true;
							continue remove;
						}
					}
				}
			}

			if (oOVocabList.size() > 1) {
				String oOArray = "," + CollectionUtil.joinStringByList(oOVocabList, ",") + ",";
				String oOProp = "," + CollectionUtil.joinStringByList(oOPropretyList, ",") + ",";
				if (blacklistMap.get("o+o").contains(oOArray)) {
					deleteFlag = true;
					return false;
				} else {
					addDyad2Result("o+o", oOArray, oOProp, result);
				}
			}
		}
		return true;
	}

	private boolean checkOS(List<HiveSymptomDyadStd> result) {
		if (oSPropertyList.contains("s") && (oSPropertyList.contains("o") || oSPropertyList.contains("oa"))) {
			// 将o+s的分词列表从后往前循环，去找匹配的核心的o
			String oSArray = ",";
			String oSProp = ",";
			String oOTemp = ",";
			List<String> multiOTemp = new ArrayList<>();
			multiOTemp.addAll(multiOCombineS);

			List<String> multiOResult = new ArrayList<>();
			boolean firstO = true;

			for (int i = oSPropertyList.size() - 1; i >= 0; i--) {
				if (oSPropertyList.get(i).indexOf("o") > -1) {
					// 循环到o属性的词
					if (!multiOTemp.isEmpty()) {
						oOTemp = "," + oSVocabList.get(i) + oOTemp;
						for (String multiO : multiOTemp) {
							if (multiO.endsWith(oOTemp)) {
								multiOResult.add(multiO);
							}
						}
						if (multiOResult.size() > 1) {
							// 核心o还有多个，将核心词列表更新，进入下次循环
							oSArray = "," + oSVocabList.get(i) + oSArray;
							oSProp = "," + oSPropertyList.get(i) + oSProp;
							multiOTemp = multiOResult;
							multiOResult = new ArrayList<>();
						} else if (multiOResult.size() == 1) {
							// 核心o只有一个则已获取结果，不再获取o
							oSArray = "," + oSVocabList.get(i) + oSArray;
							oSProp = "," + oSPropertyList.get(i) + oSProp;
							multiOTemp.clear();
						} else {
							// 已经没有匹配的词了，若当前是第一次获取o的词，则将改词加入，然后将可能的核心o清空
							if (firstO) {
								oSArray = "," + oSVocabList.get(i) + oSArray;
								oSProp = "," + oSPropertyList.get(i) + oSProp;
							}
							multiOTemp = new ArrayList<>();
						}
					}

					firstO = false;
				} else {
					oSArray = "," + oSVocabList.get(i) + oSArray;
					oSProp = "," + oSPropertyList.get(i) + oSProp;
				}
			}

			if (blacklistMap.get("o+s").contains(oSArray)) {
				deleteFlag = true;
				return false;
			} else {
				addDyad2Result("o+s", oSArray, oSProp, result);
			}
		}

		return true;
	}
}
